<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
	xmlns:xs="http://www.w3.org/2001/XMLSchema" 
	xmlns:sqlml ="http://MySQL-DbML.org"
	xmlns:aorml="http://AOR-AppML.org">
	<xsl:output name="php" method="text" />
    <xsl:output name="xml" method="xml" />
	<xsl:variable name="break"><xsl:text>
</xsl:text></xsl:variable>
    <xsl:variable name="tab"><xsl:text>    </xsl:text></xsl:variable>
    <!--path for helium: /srv/www/webapps/oryx/test/ -->
    <!-- path on local windows: file:///Program Files/apache-tomcat6/webapps/oryx/test/ -->
    <xsl:variable name="filepath"><xsl:text></xsl:text></xsl:variable>
    <xsl:function name="aorml:upperFirst" as="xs:string?">
        <xsl:param name="trans" as="xs:string?"></xsl:param>
        <xsl:sequence select="concat(upper-case(substring($trans,1,1)),substring($trans,2))"/>
    </xsl:function>
    <xsl:function name="aorml:lowerFirst" as="xs:string?">
        <xsl:param name="trans" as="xs:string?"></xsl:param>
        <xsl:sequence select="concat(lower-case(substring($trans,1,1)),substring($trans,2))"/>
    </xsl:function>
    
	<xsl:template match="/">
       <xsl:result-document href="{$filepath}MySQLML.xml" format="xml">
            <xsl:call-template name="generateSQLML" />
	   </xsl:result-document>
	</xsl:template>
    
	<xsl:template name="generateSQLML">
	   <xsl:value-of select="$break" />
        <sqlml:Db-Model xmlns:sqlml ="http://MySQL-DbML.org"        
        xmlns:p="http://purl.org/dc/elements/1.1/" 
        xmlns:xml="http://www.w3.org/XML/1998/namespace" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:schemaLocation="http://MySQL-DbML.org MySQL-DbML.xsd">
        <xsl:value-of select="$break"></xsl:value-of>
        <xsl:for-each select="/aorml:Application/aorml:ObjectType">
            <xsl:value-of select="concat($break,$tab)" />
            <xsl:element name="sqlml:ObjectTable">
                <xsl:attribute name="name"><xsl:value-of select="@name" /></xsl:attribute>                
                <xsl:for-each select="aorml:Attribute | aorml:EnumerationProperty">
                    <xsl:value-of select="concat($break,$tab,$tab)" />
                    <xsl:if test="name() = 'aorml:Attribute'">
                        <!-- multi valued attributes have to put in a new ObjectTable-->
                        <xsl:element name="sqlml:Attribute">
                            <xsl:attribute name="name"><xsl:value-of select="@name" /></xsl:attribute>
                            <xsl:attribute name="type">
                                <xsl:call-template name="getSQLType" >
                                    <xsl:with-param name="aorType">
                                        <xsl:value-of select="@type" />
                                    </xsl:with-param>
                                </xsl:call-template>
                            </xsl:attribute>
                            <xsl:if test="@isStandardID = 'true'">
                                <xsl:attribute name="isPrimaryKey">true</xsl:attribute>
                            </xsl:if>
                            <xsl:if test="not(not(@lowerMultiplicity)or(@lowerMultiplicity = '0'))">
                                <xsl:attribute name="isMandatory">true</xsl:attribute>
                            </xsl:if>
                            <xsl:if test="@typeSize">
                                <xsl:attribute name="typeSize" select="@typeSize" />
                            </xsl:if>
                            <xsl:if test="@minValue">
                                <xsl:attribute name="minValue" select="@minValue" />
                            </xsl:if>
                            <xsl:if test="@maxValue">
                                <xsl:attribute name="maxValue" select="@maxValue" />
                            </xsl:if>
                        </xsl:element>
                    </xsl:if>
                <!-- Enumeration -->
                    <xsl:if test="name() = 'aorml:EnumerationProperty'">
                        <xsl:variable name="enumName" select="@type" />
                        <xsl:element name="sqlml:Attribute">
                            <xsl:attribute name="name"><xsl:value-of select="@name" /></xsl:attribute>
                            <xsl:variable name="enum">
                                <xsl:for-each select="//aorml:Enumeration[@name = $enumName]/aorml:EnumerationLiteral">
                                    <xsl:value-of select="." />
                                    <xsl:if test="position() != last()">                        
                                        <xsl:text> </xsl:text>
                                    </xsl:if>  
                                </xsl:for-each>
                            </xsl:variable>
                            <xsl:attribute name="type" select="$enum"></xsl:attribute>
                        </xsl:element>
                    </xsl:if>
                </xsl:for-each>
                
                <!-- attributes from superType -->
                <xsl:if test="@superType">
                    <xsl:call-template name="getSuperIDAttributes">
                        <xsl:with-param name="objectName"><xsl:value-of select="@superType" /></xsl:with-param>                        
                    </xsl:call-template>
                    <!-- foreign keys from superType -->
                    <xsl:call-template name="getSuperFK">
                        <xsl:with-param name="objectName"><xsl:value-of select="@superType" /></xsl:with-param>
                        <xsl:with-param name="directSuper"><xsl:value-of select="@superType" /></xsl:with-param>
                    </xsl:call-template>
                </xsl:if>
                
            <!-- keys of functional associations as attributes-->
                <xsl:variable name="objectTypeName">
                    <xsl:value-of select="@name"></xsl:value-of>
                </xsl:variable>
                <!-- from association with objectType as domain -->
                <xsl:for-each select="//aorml:BiNavigableAssociation[@domain=$objectTypeName][(@rangeMultiplicity='1')and
                    (@domainMultiplicity='*' or @domainMultiplicity='1..*' )]
                    |//aorml:NavigableAssociation[@domain=$objectTypeName][(@rangeMultiplicity='1')and
                    (@domainMultiplicity='*' or @domainMultiplicity='1..*' )]">
                    <xsl:call-template name="getFuncKeyAttribute">
                        <xsl:with-param name="objectTypeName">
                            <xsl:value-of select="@range"></xsl:value-of>
                        </xsl:with-param>
                        <xsl:with-param name="roleName">
                            <xsl:value-of select="@rangeRoleName"></xsl:value-of>
                        </xsl:with-param>
                    </xsl:call-template>
                </xsl:for-each>
                <!-- from association with objectType as range -->
                <xsl:for-each select="//aorml:BiNavigableAssociation[@range=$objectTypeName][(@domainMultiplicity='1')and
                    (@rangeMultiplicity='*' or @rangeMultiplicity='1..*' )]
                    |//aorml:NavigableAssociation[@range=$objectTypeName][(@domainMultiplicity='1')and
                    (@rangeMultiplicity='*' or @rangeMultiplicity='1..*' )]">
                    <xsl:call-template name="getFuncKeyAttribute">
                        <xsl:with-param name="objectTypeName">
                            <xsl:value-of select="@domain"></xsl:value-of>
                        </xsl:with-param>
                        <xsl:with-param name="roleName">
                            <xsl:value-of select="@domainRoleName"></xsl:value-of>
                        </xsl:with-param>
                    </xsl:call-template>
                </xsl:for-each>
                
                <!-- attributes from functional and inverse functional association 
                    with objectType as domain -->
                <xsl:for-each select="//aorml:BiNavigableAssociation[@domain=$objectTypeName]
                    [(@rangeMultiplicity='1' or @rangeMultiplicity='0..1')and
                    (@domainMultiplicity='1' or @domainMultiplicity='0..1' )]
                    |//aorml:NavigableAssociation[@domain=$objectTypeName]
                    [(@rangeMultiplicity='1' or @rangeMultiplicity='0..1')and
                    (@domainMultiplicity='1' or @domainMultiplicity='0..1' )]">
                    <xsl:call-template name="getFuncKeyAttribute">
                        <xsl:with-param name="objectTypeName">
                            <xsl:value-of select="@range"></xsl:value-of>
                        </xsl:with-param>
                        <xsl:with-param name="roleName">
                            <xsl:value-of select="@rangeRoleName"></xsl:value-of>
                        </xsl:with-param>
                    </xsl:call-template>
                </xsl:for-each>
            <!-- keys of functional associations as foreignKeys-->
                <!-- foreignKeys from association with objectType as domain -->
                <xsl:for-each select="//aorml:BiNavigableAssociation[@domain=$objectTypeName][(@rangeMultiplicity='1')and
                    (@domainMultiplicity='*' or @domainMultiplicity='1..*' )]
                    |//aorml:NavigableAssociation[@domain=$objectTypeName][(@rangeMultiplicity='1')and
                    (@domainMultiplicity='*' or @domainMultiplicity='1..*' )]">
                    <xsl:call-template name="getFuncForeignKey">
                        <xsl:with-param name="objectTypeName">
                            <xsl:value-of select="@range"></xsl:value-of>
                        </xsl:with-param>
                        <xsl:with-param name="roleName">
                            <xsl:value-of select="@rangeRoleName"></xsl:value-of>
                        </xsl:with-param>
                    </xsl:call-template>
                </xsl:for-each>
                <!-- foreignKeys from association with objectType as range -->
                <xsl:for-each select="//aorml:BiNavigableAssociation[@range=$objectTypeName][(@domainMultiplicity='1')and
                    (@rangeMultiplicity='*' or @rangeMultiplicity='1..*' )]
                    |//aorml:NavigableAssociation[@range=$objectTypeName][(@domainMultiplicity='1')and
                    (@rangeMultiplicity='*' or @rangeMultiplicity='1..*' )]">
                    <xsl:call-template name="getFuncForeignKey">
                        <xsl:with-param name="objectTypeName">
                            <xsl:value-of select="@domain"></xsl:value-of>
                        </xsl:with-param>
                        <xsl:with-param name="roleName">
                            <xsl:value-of select="@domainRoleName"></xsl:value-of>
                        </xsl:with-param>
                    </xsl:call-template>
                </xsl:for-each>
                <!-- foreignKeys from functional and inverse functional association 
                    with objectType as domain -->
                <xsl:for-each select="//aorml:BiNavigableAssociation[@domain=$objectTypeName]
                    [(@rangeMultiplicity='1' or @rangeMultiplicity='0..1')and
                    (@domainMultiplicity='1' or @domainMultiplicity='0..1' )]
                    |//aorml:NavigableAssociation[@domain=$objectTypeName]
                    [(@rangeMultiplicity='1' or @rangeMultiplicity='0..1')and
                    (@domainMultiplicity='1' or @domainMultiplicity='0..1' )]">
                    <xsl:call-template name="getFuncForeignKey">
                        <xsl:with-param name="objectTypeName">
                            <xsl:value-of select="@range"></xsl:value-of>
                        </xsl:with-param>
                        <xsl:with-param name="roleName">
                            <xsl:value-of select="@rangeRoleName"></xsl:value-of>
                        </xsl:with-param>
                    </xsl:call-template>
                </xsl:for-each>
                <xsl:value-of select="concat($break,$tab)" />
            </xsl:element>  
            <!-- create ObjectTables for multi valued attributes -->
            <xsl:for-each select="aorml:Attribute[@upperMultiplicity and (not(@upperMultiplicity = '1' or @upperMultiplicity = '0'))]">
                <xsl:value-of select="concat($break,$tab)" />
                <xsl:element name="sqlml:ObjectTable">
                    <xsl:attribute name="name"><xsl:value-of select="aorml:upperFirst(@name)" /></xsl:attribute>
                    <xsl:element name="sqlml:Attribute">
                        <xsl:attribute name="name"><xsl:value-of select="@name" /></xsl:attribute>
                        <xsl:attribute name="type">
                            <xsl:call-template name="getSQLType" >
                                <xsl:with-param name="aorType">
                                    <xsl:value-of select="@type" />
                                </xsl:with-param>
                            </xsl:call-template>
                            </xsl:attribute>
                    </xsl:element>
                    <!-- keys of multivalued as attributes-->
                    <xsl:for-each select="../aorml:Attribute[@isStandardID ='true']">
                        <xsl:value-of select="concat($break,$tab,$tab)" />
                        <xsl:element name="sqlml:Attribute">
                            <xsl:attribute name="name"><xsl:value-of select="@name" /></xsl:attribute>
                            <xsl:attribute name="type">
                                <xsl:call-template name="getSQLType" >
                                    <xsl:with-param name="aorType">
                                        <xsl:value-of select="@type" />
                                    </xsl:with-param>
                                </xsl:call-template>
                            </xsl:attribute>
                        </xsl:element>
                    </xsl:for-each>
                    <!-- keys of multivalued as foreign keys-->
                    <xsl:for-each select="../aorml:Attribute[@isStandardID ='true']">
                        <xsl:value-of select="concat($break,$tab,$tab)" />
                        <xsl:element name="sqlml:ForeignKey">
                            <xsl:attribute name="foreignKeyAttribute"><xsl:value-of select="@name" /></xsl:attribute>
                            <xsl:attribute name="referencedTable"><xsl:value-of select="../@name" /></xsl:attribute>
                            <xsl:attribute name="referencedAttribute"><xsl:value-of select="@name" /></xsl:attribute>
                        </xsl:element>
                    </xsl:for-each>
                    <xsl:value-of select="concat($break,$tab)" />
                </xsl:element>
            </xsl:for-each>
        </xsl:for-each>
        <!-- associationTables from many to many -->
        <xsl:for-each select="//aorml:BiNavigableAssociation[(@rangeMultiplicity='*' or @rangeMultiplicity='1..*')and
                (@domainMultiplicity='*' or @domainMultiplicity='1..*')]
                |//aorml:NavigableAssociation[(@rangeMultiplicity='*' or @rangeMultiplicity='1..*')and
                (@domainMultiplicity='*' or @domainMultiplicity='1..*')]">
            <xsl:value-of select="concat($break,$tab)" />
            <xsl:element name="sqlml:AssociationTable">
                <xsl:attribute name="name">
                    <xsl:value-of select="@name"></xsl:value-of>
                    <xsl:if test="not(@name)">
                        <xsl:value-of select="@domain"></xsl:value-of>
                        <xsl:value-of select="@range"></xsl:value-of>
                    </xsl:if>
                </xsl:attribute>
                <!-- key attribute of domain as attribute -->
                <xsl:call-template name="getKeyAttribute">
                    <xsl:with-param name="objectTypeName">
                        <xsl:value-of select="@domain"></xsl:value-of>
                    </xsl:with-param>
                    <xsl:with-param name="roleName">
                        <xsl:value-of select="@domainRoleName"></xsl:value-of>
                    </xsl:with-param>
                </xsl:call-template>
                <!-- key attribute of range as attribute -->
                <xsl:call-template name="getKeyAttribute">
                    <xsl:with-param name="objectTypeName">
                        <xsl:value-of select="@range"></xsl:value-of>
                    </xsl:with-param>
                    <xsl:with-param name="roleName">
                        <xsl:value-of select="@rangeRoleName"></xsl:value-of>
                    </xsl:with-param>
                </xsl:call-template>
                <!-- key of domain as foreign key -->
                <xsl:call-template name="getForeignKey">
                    <xsl:with-param name="objectTypeName">
                        <xsl:value-of select="@domain"></xsl:value-of>
                    </xsl:with-param>
                    <xsl:with-param name="roleName">
                        <xsl:value-of select="@domainRoleName"></xsl:value-of>
                    </xsl:with-param>
                </xsl:call-template>
                <!-- key of range as foreign key -->
                <xsl:call-template name="getForeignKey">
                    <xsl:with-param name="objectTypeName">
                        <xsl:value-of select="@range"></xsl:value-of>
                    </xsl:with-param>
                    <xsl:with-param name="roleName">
                        <xsl:value-of select="@rangeRoleName"></xsl:value-of>
                    </xsl:with-param>
                </xsl:call-template>
                <xsl:value-of select="concat($break,$tab)" />
            </xsl:element>
        </xsl:for-each>  
        <xsl:value-of select="$break" />   
        </sqlml:Db-Model>
    </xsl:template>
    <xsl:template name="getSQLType">
       <xsl:param name="aorType"></xsl:param>
       <xsl:choose>
           <xsl:when test="$aorType = 'String'">
               <xsl:text>VARCHAR</xsl:text>
           </xsl:when>
           <xsl:when test="$aorType = 'Integer'">
               <xsl:text>INT</xsl:text>
           </xsl:when>
           <xsl:when test="$aorType = 'Float'">
               <xsl:text>FLOAT</xsl:text>
           </xsl:when>
           <xsl:when test="$aorType = 'Boolean'">
               <xsl:text>BOOL</xsl:text>
           </xsl:when>
           <xsl:when test="$aorType = 'Date'">
               <xsl:text>DATE</xsl:text>
           </xsl:when>
           <xsl:when test="$aorType = 'Time'">
               <xsl:text>TIME</xsl:text>
           </xsl:when>
           <xsl:when test="$aorType = 'DateTime'">
               <xsl:text>DATETIME</xsl:text>
           </xsl:when>  
           <xsl:when test="$aorType = 'URL'">
               <xsl:text>VARCHAR</xsl:text>
           </xsl:when>  
           <xsl:when test="$aorType = 'Tel'">
               <xsl:text>VARCHAR</xsl:text>
           </xsl:when> 
           <xsl:when test="$aorType = 'Email'">
               <xsl:text>VARCHAR</xsl:text>
           </xsl:when> 
       </xsl:choose>
    </xsl:template>
    <xsl:template name="getSuperIDAttributes">
        <xsl:param name="objectName"></xsl:param>
        <xsl:if test="//aorml:ObjectType[@name=$objectName][not(@superType)]">
            <xsl:for-each select="//aorml:ObjectType[@name=$objectName]/aorml:Attribute[@isStandardID='true']">
                <xsl:value-of select="concat($break,$tab,$tab)" />
                <xsl:element name="sqlml:Attribute">
                    <xsl:attribute name="name"><xsl:value-of select="@name" /></xsl:attribute>
                    <xsl:attribute name="type">
                        <xsl:call-template name="getSQLType" >
                            <xsl:with-param name="aorType">
                                <xsl:value-of select="@type" />
                            </xsl:with-param>
                        </xsl:call-template>
                    </xsl:attribute>
                    <xsl:attribute name="isPrimaryKey">true</xsl:attribute>
                    <xsl:if test="@typeSize">
                        <xsl:attribute name="typeSize" select="@typeSize" />
                    </xsl:if>                    
                </xsl:element>
            </xsl:for-each>
        </xsl:if>
        <xsl:if test="//aorml:ObjectType[@name=$objectName][@superType]">
            <xsl:call-template name="getSuperIDAttributes">
                <xsl:with-param name="objectName">
                    <xsl:value-of select="@superType"></xsl:value-of>
                </xsl:with-param>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
    <xsl:template name="getSuperFK">
        <xsl:param name="objectName"></xsl:param>
        <xsl:param name="directSuper"></xsl:param>
        <xsl:if test="//aorml:ObjectType[@name=$objectName][not(@superType)]">
            <xsl:for-each select="//aorml:ObjectType[@name=$objectName]/aorml:Attribute[@isStandardID='true']">
                <xsl:value-of select="concat($break,$tab,$tab)" />
                <xsl:element name="sqlml:ForeignKey">
                    <xsl:attribute name="foreignKeyAttribute"><xsl:value-of select="@name" /></xsl:attribute>
                    <xsl:attribute name="referencedTable">
                        <xsl:value-of select="$directSuper"></xsl:value-of>
                    </xsl:attribute> 
                    <xsl:attribute name="referencedAttribute">
                        <xsl:value-of select="@name"></xsl:value-of>
                    </xsl:attribute>                
                </xsl:element>
            </xsl:for-each>
        </xsl:if>
        <xsl:if test="//aorml:ObjectType[@name=$objectName][@superType]">
            <xsl:call-template name="getSuperFK">
                <xsl:with-param name="objectName">
                    <xsl:value-of select="@superType"></xsl:value-of>
                </xsl:with-param>
                <xsl:with-param name="directSuper">
                    <xsl:value-of select="@directSuper"></xsl:value-of>
                </xsl:with-param>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
    <xsl:template name="getKeyAttribute">
        <xsl:param name="objectTypeName"></xsl:param>
        <xsl:param name="roleName"></xsl:param>
        <xsl:for-each select="//aorml:ObjectType[@name=$objectTypeName]/aorml:Attribute[@isStandardID='true']">
                <xsl:value-of select="concat($break,$tab,$tab)" />
                <xsl:element name="sqlml:Attribute">
                    <xsl:attribute name="name">
                        <xsl:value-of select="$roleName" />
                        <xsl:if test="($roleName = '' or not($roleName))">
                            <xsl:value-of select="aorml:lowerFirst($objectTypeName)" />
                        </xsl:if>
                    </xsl:attribute>
                    <xsl:attribute name="type">
                        <xsl:call-template name="getSQLType" >
                            <xsl:with-param name="aorType">
                                <xsl:value-of select="@type" />
                            </xsl:with-param>
                        </xsl:call-template>
                    </xsl:attribute>
                    <xsl:if test="@typeSize">
                        <xsl:attribute name="typeSize" select="@typeSize" />
                    </xsl:if>
                </xsl:element>
            </xsl:for-each>
    </xsl:template>
    <xsl:template name="getForeignKey">
        <xsl:param name="objectTypeName"></xsl:param>
        <xsl:param name="roleName"></xsl:param>
        <xsl:for-each select="//aorml:ObjectType[@name=$objectTypeName]/aorml:Attribute[@isStandardID='true']">
                <xsl:value-of select="concat($break,$tab,$tab)" />
                <xsl:element name="sqlml:ForeignKey">
                    <xsl:attribute name="foreignKeyAttribute">
                        <xsl:value-of select="$roleName" />
                        <xsl:if test="($roleName = '' or not($roleName))">
                            <xsl:value-of select="aorml:lowerFirst($objectTypeName)" />
                        </xsl:if>
                    </xsl:attribute>
                    <xsl:attribute name="referencedTable">
                        <xsl:value-of select="$objectTypeName"></xsl:value-of>
                    </xsl:attribute>
                    <xsl:attribute name="referencedAttribute">
                        <xsl:value-of select="@name"></xsl:value-of>
                    </xsl:attribute>
                </xsl:element>
            </xsl:for-each>
    </xsl:template>
    <xsl:template name="getFuncKeyAttribute">
        <xsl:param name="objectTypeName"></xsl:param>
        <xsl:param name="roleName"></xsl:param>
        <xsl:for-each select="//aorml:ObjectType[@name=$objectTypeName]/aorml:Attribute[@isStandardID='true']">
                <xsl:value-of select="concat($break,$tab,$tab)" />
                <xsl:element name="sqlml:Attribute">
                    <xsl:attribute name="name">
                        <xsl:value-of select="$roleName" />
                        <xsl:if test="($roleName = '' or not($roleName))">
                            <xsl:value-of select="aorml:lowerFirst($objectTypeName)" />
                        </xsl:if>
                    </xsl:attribute>
                    <xsl:attribute name="type">
                        <xsl:call-template name="getSQLType" >
                            <xsl:with-param name="aorType">
                                <xsl:value-of select="@type" />
                            </xsl:with-param>
                        </xsl:call-template>
                    </xsl:attribute>
                    <xsl:if test="@typeSize">
                        <xsl:attribute name="typeSize" select="@typeSize" />
                    </xsl:if>
                </xsl:element>
            </xsl:for-each>
    </xsl:template>
    <xsl:template name="getFuncForeignKey">
        <xsl:param name="objectTypeName"></xsl:param>
        <xsl:param name="roleName"></xsl:param>
        <xsl:for-each select="//aorml:ObjectType[@name=$objectTypeName]/aorml:Attribute[@isStandardID='true']">
                <xsl:value-of select="concat($break,$tab,$tab)" />
                <xsl:element name="sqlml:ForeignKey">
                    <xsl:attribute name="foreignKeyAttribute">
                        <xsl:value-of select="$roleName" />
                        <xsl:if test="($roleName = '' or not($roleName))">
                            <xsl:value-of select="aorml:lowerFirst($objectTypeName)" />
                        </xsl:if>
                    </xsl:attribute>
                    <xsl:attribute name="referencedTable">
                        <xsl:value-of select="$objectTypeName"></xsl:value-of>
                    </xsl:attribute>
                    <xsl:attribute name="referencedAttribute">
                        <xsl:value-of select="@name"></xsl:value-of>
                    </xsl:attribute>
                </xsl:element>
            </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>